/*
 * QObjectDelegate.cpp  0.4.0 / Nov 14, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
#include "QObjectDelegate.h"

// QObjectDelegate :: Protected Constructors. ----------------------------------

/*!
 * \brief Constructs new QObjectDelegate object.
 *
 * \param env the JNIEnv pointer
 * \param jniObj the java object
 * \param qObj the Qt object
 *
 * \exception OutOfMemoryError
 */
QObjectDelegate::QObjectDelegate(JNIEnv *env, jobject jniObj, QObject *qObj)
  : QObject(), m_jniObject(new JNIObject(env, jniObj)), m_qObject(0),
    m_notifyDelete(true)
{
  if (qObj) {
    setQObject(qObj);
  }
}

/*!
 * \brief Constructs new QObjectDelegate object.
 *
 * \param env the JNIEnv pointer
 * \param jniObj the java object
 *
 * \exception OutOfMemoryError
 */
QObjectDelegate::QObjectDelegate(JNIEnv *env, jobject jniObj)
  : QObject(), m_jniObject(new JNIObject(env, jniObj)), m_qObject(0),
    m_notifyDelete(true)
{
  // empty constructor body
}

// QObjectDelegate :: Protected Destructor. ------------------------------------

/*!
 * \brief Destroys the QObjectDelegate object.
 */
QObjectDelegate::~QObjectDelegate()
{
  if (m_qObject) {
    delete m_qObject;
  }
}

// QObjectDelegate :: Private Constructor. -------------------------------------

QObjectDelegate::QObjectDelegate(const QObjectDelegate &)
  : QObject()
{
  // copy constructor is disabled
}

// QObjectDelegate :: Public Member Functions. ---------------------------------

/*!
 * \brief Sets the object name.
 *
 * \param env the JNIEnv pointer 
 * \param name the object name 
 */
void QObjectDelegate::setName(JNIEnv *env, jstring name)
{
  Q_ASSERT(env);
  Q_ASSERT(m_qObject);
  m_qObject->setObjectName(QStringAdapter(env, name));
}

/*!
 * \brief Posts the Qt event to the Qt object.
 *
 * \param e the event to be posted
 */
void QObjectDelegate::postEvent(QEvent *e)
{
  Q_ASSERT(m_qObject);
  Q_ASSERT(e);
  QCoreApplication::postEvent(m_qObject, e);
}

/*!
 * \brief Sends the Qt event to the Qt object.
 *
 * \param e the event
 */
void QObjectDelegate::sendEvent(QEvent *e)
{
  Q_ASSERT(m_qObject);
  Q_ASSERT(e);
  QCoreApplication::sendEvent(m_qObject, e);
}

/*!
 * \brief Destroys the QObjectDelegate object.
 *
 * \param env the JNIEnv pointer
 * \param notify if \c true the Java object will be notified about destroy
 */
void QObjectDelegate::destroy(JNIEnv *env, bool notify)
{
  Q_ASSERT(env);
  m_notifyDelete = notify;
  if (m_jniObject->isSameThread(env)) {
    delete this;  // OK - referenced only from java
  } else {
    deleteLater();
  }
}

// QObjectDelegate :: Public Static Member Function. ---------------------------

/*!
 * \brief Initializes QObjectDelegate class.
 *
 * \param env the JNIEnv pointer
 * \param cls the AbstractDisposeable java class
 *
 * \exception FatalError if failed
 */
void QObjectDelegate::initialize(JNIEnv *env, jclass cls)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT(!sm_disposeMID);
  if (!INIT_MID(dispose, cls, "()V")) {
    FATAL_LOGGED_ERROR("QObjectDelegate initialization failed");
  }
}

// QObjectDelegate :: Protected Member Functions. ------------------------------

/*!
 * \brief Returns the JNI delegate of the Cute4j object.
 *
 * \return the delegate of the Cute4j object
 */
jlong QObjectDelegate::delegatePointer()
{
  return m_jniObject->getLongField(delegatePointerFID());
}

/*!
 * \brief Object destroyed slot.
 *
 * \return qObj the destroyed object
 */
void QObjectDelegate::objectDestroyed(QObject *qObj)
{
  if (qObj == m_qObject) {
    m_qObject = 0;
    deleteLater();
  }
}

/*!
 * \brief Sets the JNI delegate of the Cute4j object.
 *
 * \param delegatePointer the delegate of the Cute4j object
 */
void QObjectDelegate::setDelegatePointer(jlong delegatePointer)
{
  m_jniObject->setLongField(delegatePointerFID(), delegatePointer);
}

/*!
 * \brief Sets Qt object.
 *
 * \param qObj the Qt object
 */
void QObjectDelegate::setQObject(QObject *qObj)
{
  if (m_qObject) {
    m_qObject->removeEventFilter(this);
    m_qObject->setProperty(DELEGATE_PROPERTY_NAME, INVALID_QVARIANT);
    disconnect(m_qObject, SIGNAL(destroyed(QObject *)),
               SLOT(objectDestroyed(QObject *)));
  }
  if (qObj) {
    m_qObject = qObj;
    connect(qObj, SIGNAL(destroyed(QObject *)), this,
            SLOT(objectDestroyed(QObject *)));
    qObj->setProperty(DELEGATE_PROPERTY_NAME,
                      qVariantFromValue<QObject *>(this));
    qObj->installEventFilter(this);
  } else {
    m_qObject = 0;
  }
}

// QObjectDelegate :: Private Static Data Member. ------------------------------

jmethodID QObjectDelegate::sm_disposeMID = 0;

// QObjectDelegate :: Public Static Data Members. ------------------------------

const char *const QObjectDelegate::DELEGATE_PROPERTY_NAME = "QObjectDelegate";
const QVariant QObjectDelegate::INVALID_QVARIANT(QVariant::Invalid);
